﻿# importing required modules
import os, time, shutil, subprocess


class log_folder_dir:
    '类:生产log每日文件夹'

    path_7za = r'.\7z2201-extra\7za.exe'

    def __init__(self, root: str, relative_path: list[str], save_level: int):
        # C:\AA1 Result=root / BYD X1F=level 1/ 2023=level 2。。。
        # C:\AA1 Result\BYD X1F\2023\08\11
        dash = '_'
        slash = '\\'
        self.new_name = dash.join(relative_path)
        self.path = root + slash + slash.join(relative_path)
        self.target_path = root + slash + slash.join(relative_path[:save_level])
        self.m_time = os.stat(self.path).st_mtime

    def clean_sweep(self, time_limit) -> bool:
        mark = '-cleaned'
        cleaned = 0
        current_time = int(time.time())
        # C:\AA1 Result\BYD X1F\2023\08\11=>Root path(day)
        # Root/part folder => Part path
        # Part path/file_in_part => file_in_part_path
        for part_folder in os.listdir(self.path):
            part_path = os.path.join(self.path, part_folder)
            if part_folder[-len(mark) :] == mark or os.path.isfile(part_path):
                continue
            part_time = int(os.stat(part_path).st_mtime)
            if current_time - part_time < time_limit:
                continue
            for file_in_part in os.listdir(part_path):
                file_in_part_path = os.path.join(part_path, file_in_part)
                if file_in_part[:5] == 'Sweep' and os.path.isdir(file_in_part_path):
                    for bmpfile in os.listdir(file_in_part_path):
                        if bmpfile[-4:] == '.bmp':
                            os.remove(os.path.join(file_in_part_path, bmpfile))
            os.rename(part_path, part_path + mark)
            cleaned += 1
        return cleaned

    def sevenzip(self, remian_time: int) -> int:
        """Archive file with 7za.exe

        Args:
            remian_time (int): Time to Archive

        Returns:
            int: 0 -- File Archived Skipped \n
            int: 1 -- Archived successfuly \n
            int:-1 -- Archived with some error \n
            int:-2 -- Another archiving process is working!
        """
        now = time.time()
        if (now - self.m_time) > remian_time:
            timemark = "-" + time.strftime("%y%m%d%H%M%S", time.localtime(now))
            archive_list_txt = self.path + "\\Archive Lists_By_Yingestech.txt"
            if os.path.exists(archive_list_txt):
                try:
                    os.remove(archive_list_txt)
                except:
                    return -2
            content = (
                self.path
                + ' ==> '
                + self.new_name
                + timemark
                + '.7z - By_Yingestech\r\nList:\n'
                + '\n'.join(os.listdir(self.path))
            )
            with open(archive_list_txt, 'a+', encoding='utf-8') as fs:
                fs.write(content)
            alt = open(archive_list_txt)
            newpath_newname = self.target_path + "\\" + self.new_name + timemark + ".7z"
            new_old_Path_Name = "\"" + newpath_newname + "\" \"" + self.path + "\""
            path_7za = "\"" + self.path_7za + "\""
            cmd = path_7za + " a -bso2 -bse2 -bsp2 -mmt2 " + new_old_Path_Name
            ret = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
            for line in iter(ret.stdout.readline, 'b'):
                line = line.rstrip().decode('utf8')
                if (subprocess.Popen.poll(ret) is not None) and line == "":
                    break
            ret.stdout.close()
            alt.close()
            if ret.returncode == 0:
                print(newpath_newname + " archived!\n")
                shutil.rmtree(self.path)  # delete zipped file
                return 1
            else:
                return -1
        else:
            return 0


class log_folder_dirs:
    def __init__(self, root_dir: str, list_level=4, save_level=2):
        self.list_level = list_level
        self.save_level = save_level
        if self.list_level < self.save_level:
            print("Error:Parameter intut with issue, required:list_level>=save_level")
            return
        self.root_dir = root_dir
        self.part_folder_list = self.get_all_folder(self)

    def get_all_folder(
        self, working_dir="", rel_path: list[str] = [], i=1
    ) -> list[log_folder_dir]:
        empty_lis: list[str] = []
        if i > self.list_level:
            return empty_lis
        folder_lis: list[log_folder_dir] = []
        if i == 1:
            folders = os.listdir(self.root_dir)
            working_dir = self.root_dir
        else:
            folders = os.listdir(working_dir)
        for folder in folders:
            re_path_add = rel_path + [folder]
            root_add_folder = os.path.join(working_dir, folder)
            if os.path.isfile(root_add_folder):
                continue
            if i < self.list_level:
                folder_lis = folder_lis + self.get_all_folder(
                    root_add_folder, re_path_add, i + 1
                )
            else:
                folder_lis.append(
                    log_folder_dir(self.root_dir, re_path_add, self.save_level)
                )
        return folder_lis

    def clean_sweeps(self, remain_time):
        cleaned = 0
        for folder in self.part_folder_list:
            cleaned = cleaned + folder.clean_sweep(remain_time)
        return cleaned

    def sevenzips(self, remain_time, zips_in_one_time=5) -> int:
        """Archive Logs

        Args:
            remain_time (_type_): _description_
            zips_in_one_time (int, optional): _description_. Defaults to 5.

        Returns:
            int: Archived QTY Out
            if count = -1 Zipped with Error
            if Count = -2 Zipped Terminated Bcause Other process is Running
        """
        count = 0
        for folder in self.part_folder_list:
            if count > zips_in_one_time - 1:
                break
            ar_result = folder.sevenzip(remain_time)
            if ar_result == 1:
                count += 1
            elif ar_result == 0:
                pass
            elif ar_result == -1:
                count = -1  # error 1
                break
            elif ar_result == -2:
                count = -2  # error 2
                break
        return count


def main(log_root_dir, sweep_remain, logs_Remain, zips_in_one_time: int = 5):
    if zips_in_one_time < 0:
        print("Error:'zips_in_one_time'<0,Please Reset")
        return
    # Get the list folder
    folder_lists = log_folder_dirs(log_root_dir, 4, 2)
    # Clean Sweep folder
    cleaned = folder_lists.clean_sweeps(sweep_remain)
    if cleaned > 0:
        print(
            "Cleaned %s parts folder with Sweep remain for more then %.2f mins"
            % (cleaned, (sweep_remain / 60))
        )
    else:
        print("No sweep folder to delete")
    if zips_in_one_time == 0:
        print("zips_in_one_time = 0,No zip task!")
    else:
        archived = folder_lists.sevenzips(logs_Remain, zips_in_one_time)
        if archived == -1:
            print("Error occured,archice process stopped")
        elif archived == -2:
            print("Another archiving process is working! Please try it later\n")
        elif archived == 0:
            print("No file ready to archive!")
        else:
            print("%s files archived successfully!" % archived)


if __name__ == "__main__":
    log_root_dir = r'C:\Users\tding1\Desktop\TestResults'
    main(log_root_dir, 5, 10)
